home *** CD-ROM | disk | FTP | other *** search
- /* BLDFUNCS.C - Construct a table of the functions defined in src files.
- * Copyright (c) 1988 Marvin Hymowech
- *
- * Usage: bldfuncs file1.c file2.c ...
- * Wildcards are allowed also, e.g. *.c
- * The output table is named FUNCS.TXT
- *
- * The typist changed all function names beginning with filter_...() to
- * flt_...(). Example: filter_data() changed to flt_data(). These were
- * changed because the Mix Power C debugger only recognizes the first 8
- * characters. Hence, it will report an internal CTRACE error (can't lo-
- * cate symbol) with names like filter_ppdir() and filter_parens().
- * See the .DOC file in this .ARC file for information on setting up
- * the environment variable GETFEDIT and for getting this program to acc-
- * ept wildcards. Microsoft C has a library file that can be linked with
- * BLDFUNCS enabling wildcard input but as far as I know, Quick C and
- * Power C do not have this library file. It's called setargv. The
- * BLDFUNCS.EXE & GETF.EXE files were made with Quick C and I also suc-
- * cessfully compiled, linked, and ran them with Power C but with no wild-
- * card input accepted with either.
- * Also, see the .DOC file to see how BLDFUNCS and GETF interact.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #define LINT_ARGS
-
- #define TRUE 1
- #define FALSE 0
- #define OK 0
- #define ERROR 1
-
- /* * return values for filter functions below.
- * EOF or any character is also possible.
- */
-
- #define BRACES -2
- #define PARENS -3
- #define QUOTES -4
-
- /* function declarations for type checking */
- char *get_fn_name(char *);
- int get_names_one_file(char *, FILE *);
-
- main(argc, argv)
- int argc;
- char **argv;
- {
-
- FILE *fp_out;
- char *current_file;
- int num_files, i;
-
- if (argc < 2) {
- fprintf( stderr, "\nWrong number of parameters");
- exit(1);
- }
-
- if ( (fp_out = fopen("FUNCS.TXT", "w")) == NULL ) {
- fprintf( stderr, "Can't open %s\n", "FUNCS.TXT");
- exit(1);
- }
-
- /* build a function list for each file on the command line
- * and write the list to the file "FUNCS.TXT".
- */
-
- /* tell the user where we're at */ /* this line (<---) is below in book*/
- printf("Creating FUNCS.TXT...\n");
- num_files = argc - 1;
- for (i = 1; i <= num_files; i++) {
- /* use strlwr to lower-case name - cosmetic only */
- printf(" %30s: %3d of %3d files\n",
- current_file = strlwr (*++argv), i, num_files );
- if (get_names_one_file (current_file, fp_out ) != OK ) {
- fprintf( stderr, "\nCan't process %s", current_file);
- exit(1);
- }
- }
-
- fclose(fp_out);
- exit(0);
- }
-
- /* open the c file source_file_name, scan it for function definitions,
- * and write a listing to fp_out in the form:
- * source_file_name:
- * function-1
- * function-2 ...
- * function-n;
- * Return values: OK or ERROR
- */
-
- int get_names_one_file(source_file_name, fp_out)
- char *source_file_name;
- FILE *fp_out;
- {
-
- int line_len, c, got_fn_defn = FALSE;
- #define LINE_LEN 8192
- char line[LINE_LEN], *name_ptr, fn_name[64];
- FILE *fp_source;
-
- /* open the input source file */
- if ( (fp_source = fopen(source_file_name, "r")) == NULL)
- return ERROR;
- /* write "source file name:" */
- sprintf( line, "\n%s:", source_file_name);
- fprintf( fp_out, line);
-
- while( TRUE) {
- line_len = 0; /* using the flt_data() char stream */
- /* collect chars till a semicolon or PARENS */
- while( (c = flt_data(fp_source)) != EOF && c != ';' && c != PARENS)
- line[line_len++] = c;
- if (c == EOF)
- break;
- if (c == ';') /* Bypass externals representing data items */
- continue; /* Now we know line entered with PARENS */
- line[line_len] = 0; /* Truncate line */
-
- /* At this point, line either contains a function definition
- * or a function type declaration or something else, perhaps
- * an occurrence of parinthese in a data item definition.
- * We only want function definitions.
- */
- /* Extract the function name from this possible */
- /* function definition, and save it in fn_name */
- strcpy(fn_name, get_fn_name(line) );
- /* Exclude the case of parenthetical expressions in */
- /* a data definition, e.g. within srray brackets */
- if ( !fn_name[0])
- continue;
- /* skip white space */
- while ( (c = flt_data(fp_source)) != EOF && isspace(c) )
- ;
- if (c == ';' || c == ',') /* functs type check declaration */
- continue; /* so bypass it */
- if (c == EOF)
- break;
- /* skip any parameter declarations - */
- while (c != BRACES && c != EOF) /* eat until braces or EOF */
- c = flt_data(fp_source);
-
- /* append this function definition to the output table */
- fprintf( fp_out, "\n\t%s", fn_name);
- got_fn_defn = TRUE;
- } /* end while */
- fclose(fp_source);
- /* got_fn_defn FALSE if no functions in file */
- /* write file terminator */
- fputs( got_fn_defn ? ";\n" : "\n\t;\n", fp_out);
- return OK;
- } /* end get_names_one_file() */
-
- /* assuming that the input line ends with a function name,
- * extract and return this name (as a pointer into the input line)/
- */
- char *get_fn_name(line)
- char *line;
- {
-
- char *name_ptr;
- int len;
-
- if ( !(len = strlen(line)) )
- return line;
- name_ptr = line + len - 1;
- while (isspace(*name_ptr)) /* skip trailing white space */
- name_ptr--;
- *(name_ptr + 1) = 0; /* terminate fn name */
-
- /* function names consist entirely of alpha- */
- /* numeric chars and underscores */
- while ( (isalnum(*name_ptr) || *name_ptr == '_') && name_ptr >= line)
- name_ptr--;
- /* if this alleged function name begins */
- if ( isdigit(*++name_ptr)) /* with a digit, return an empty string */
- return( name_ptr + strlen(name_ptr) );
- return name_ptr; /* else return the function name */
- } /* end get_fn_name */
-
- /* Using the stream returned by flt_parens() as input,
- * return a character stream in which any data initialization
- * exptessions between an equals sign and a simicolon
- * have been replaced by a single semicolon.
- * This will filter out anything involving parentheses in a
- * data initialization expression, which might otherwise be
- * mistaken for a function definition.
- */
-
- int flt_data(fp_source)
- FILE *fp_source;
- {
-
- int c;
-
- if ( (c = flt_parens(fp_source)) != '=')
- return c;
- while ( (c = flt_parens(fp_source)) != ';' && c != EOF)
- ;
- return c;
- } /* end flt_data() */
-
- /* Using the stream returned by flt_curly_braces() as input,
- * reutrn a character stream in which all characters between
- * '{' and the matching '}' have been replaced by the
- * single special value PARENS (any nested parentheses within
- * this top level pair will also have been eaten).
- * This will filter out anything within the parentheses delimiting
- * the arguments in a function definition.
- */
-
- int flt_parens(fp_source)
- FILE *fp_source;
- {
-
- int paren_cnt, c;
-
- if ( (c = flt_curly_braces(fp_source)) != '(' )
- return c;
- paren_cnt = 1;
- while (paren_cnt)
- switch (flt_curly_braces(fp_source)) {
- case ')':
- paren_cnt--;
- break;
- case '(':
- paren_cnt++;
- break;
- case EOF:
- return EOF;
- }
- return PARENS;
- }
-
- /* Using the stream returned by flt_ppdir() as input,
- * return a character stream in which all characters between
- * '{' and the matching '}' have been replaced by the
- * single special value BRACES (any nested braces within
- * this top level pair will also have been eaten). This
- * will filter out anything internal to a function.
- */
-
- int flt_curly_braces(fp_source)
- FILE *fp_source;
- {
-
- int brace_cnt,c;
-
- if( (c = flt_ppdir(fp_source) ) != '{')
- return c;
- brace_cnt = 1;
- while (brace_cnt) /* wait for brace count to return to zero */
- switch (flt_ppdir(fp_source)) {
- case '}':
- brace_cnt--;
- break;
- case '{':
- brace_cnt++;
- break;
- case EOF:
- return EOF;
- }
- return BRACES; /* brace count is now zero */
- }
-
- #define MAXLINE 1024
-
- /* Using the stream returned by flt_quotes() as input,
- * return a character stream in which all preprocessor
- * directives have been eaten.
- */
-
- int flt_ppdir(fp_source)
- FILE *fp_source;
- {
-
- int c, i;
- char line [MAXLINE + 1];
-
- while (TRUE) { /* Does this line begin a preprocessor directive? */
- if ( (c = flt_quotes(fp_source)) != '#')
- return c; /* no, return character */
- /* yes, store until newline or EOF */
- if ( (c = get_ppdir_line(fp_source, line)) == EOF)
- return EOF;
- if (strncmp(line, "define", 6)) /* if not #define directives */
- continue; /* set this line */
- if (line [strlen(line) - 1] != '\\') /* If #define line */
- continue; /* ends with "\" */
- else
- while (TRUE) { /* Keep eating lines which also end with "\" */
- /* Store until newline or EOF */
- if ( (c = get_ppdir_line(fp_source, line)) == EOF)
- return EOF;
- /* Done with this #define directive if this */
- /* line is not also a continuation line */
- if ( line [strlen(line) - 1] != '\\')
- break;
- } /* end while */
- } /* end while */
- } /* end flt_ppdir() */
-
- /* Utility routine used by flt_ppdir() -
- * read the character stream using flt_quotes, storing characters
- * in the parameter "line" until EOF or '\n' is encountered.
- * Return EOF or '\n' accordingly.
- */
-
- int get_ppdir_line(fp_source, line)
- FILE *fp_source;
- char *line;
- {
-
- int i, c;
-
- for (i = 0; i < MAXLINE && (c = flt_quotes(fp_source)) != '\n'
- && c != EOF; i++)
- line[i] = c;
- line[i] = 0; /* terminate string */
- if (c == EOF)
- return EOF;
- return '\n';
- }
-
- /* Using the stream returned by flt_cmt() as input,
- * return a character stream in which any quoted character
- * or quoted string has been collapsed to the single special value QUOTES
- * to avoid considering special characters like '{', '}', '(', or ')'
- * which may occur within quotes.
- */
-
- int flt_quotes(fp_source)
- FILE *fp_source;
- {
-
- int c1, c2;
-
- if ( (c1 = flt_cmt(fp_source)) != '\'' && c1 != '"')
- return c1; /* pass char through if not single or double quote */
- while (TRUE)
- switch (c2 = flt_cmt(fp_source)) {
- case '\\': /* beginning of an escape sequence */
- flt_cmt(fp_source); /* so eat next char */
- break;
- case EOF:
- return EOF;
- default:
- if (c2 == c1) /* found end of quoted char or string */
- return QUOTES;
- } /* end switch */
- } /* end flt_quotes() */
-
- /* Returns character stream, eating comments.
- * Returns EOF if end of file.
- * Nested comments are allowed
- */
-
- int flt_cmt(fp_source)
- FILE *fp_source;
- {
-
- /* values for state */
- #define STABLE 0 /* not in process of changing the comment */
- /* level: i.e., not in the middle of a */
- /* slash-star or star-slash combination */
- #define IN_CMT_FS 1 /* got '/', looking for '*' */
- #define OUT_CMT_STAR 2 /* got '*', looking for '/' */
-
- int c, state = STABLE, cmt_level = 0;
-
- while (TRUE) {
- c = fgetc(fp_source);
- if (c == EOF)
- return EOF;
- switch (state) {
- case STABLE:
- if (c == '*')
- state = OUT_CMT_STAR;
- else if (c == '/')
- state = IN_CMT_FS;
- break;
-
- case IN_CMT_FS:
- if (c == '*') {
- state = STABLE;
- cmt_level++; /* descend one comment level */
- continue;
- }
- else if ( !cmt_level) { /* If '/' not followed by '*' */
- ungetc (c, fp_source); /* push back this char */
- return '/'; /* and return the '/' */
- }
- else if (c != '/') /* stay in state IN_CMT_FS */
- state = STABLE; /* if next char is '/' as well */
- break;
-
- case OUT_CMT_STAR:
- if (c == '/') {
- cmt_level--; /* ascend one comment level */
- state = STABLE;
- continue;
- }
- else if ( !cmt_level) { /* If '*' not followed by '/' */
- ungetc (c, fp_source); /* push back this char */
- return '*'; /* and return the '*' */
- }
- else if (c != '*') /* stay in state IN_CMT_FS */
- state = STABLE; /* if next char is '*' as well */
- break;
- } /* end switch */
- if (state == STABLE && !cmt_level) /* if outside any comment */
- return c; /* return character */
- } /* end while */
- } /* end flt_cmt() */
-
-